package com.ctosb.classviewer.clazz;

import com.ctosb.classviewer.ClassReader;
import com.ctosb.classviewer.clazz.attr.Attribute_info;
import com.ctosb.classviewer.clazz.cp.CONSTANT_Class_info;
import com.ctosb.classviewer.clazz.cp.Cp_info;
import com.ctosb.classviewer.clazz.util.Attribute_infoParse;
import lombok.Data;
import lombok.experimental.Accessors;

/**
 * classfile
 */
@Data
@Accessors(chain = true)
public class ClassFile implements Parseable {
    private int magic;
    private short minor_version;
    private short major_version;
    private short constant_pool_count;
    /**
     * constant_pool_count-1
     */
    private Cp_info constant_pool[];
    private short access_flags;
    private short this_class;
    private short super_class;
    private short interfaces_count;
    /**
     * interfaces_count
     */
    private short interfaces[];
    private short fields_count;
    /**
     * fields_count
     */
    private Field_info fields[];
    private short methods_count;
    /**
     * methods_count
     */
    private Method_info methods[];
    private short attributes_count;
    /**
     * attributes_count
     */
    private Attribute_info attributes[];

    @Override
    public ClassFile parse(ClassReader classReader) {
        this.magic = classReader.readInt();
        this.minor_version = classReader.readShort();
        this.major_version = classReader.readShort();
        this.constant_pool_count = classReader.readShort();
        this.constant_pool = classReader.readCpInfos(this.constant_pool_count, this);
        this.access_flags = classReader.readShort();
        this.this_class = classReader.readShort();
        this.super_class = classReader.readShort();
        this.interfaces_count = classReader.readShort();
        this.interfaces = classReader.readInterfaces(this.interfaces_count);
        this.fields_count = classReader.readShort();
        this.fields = classReader.readFields(this.fields_count, this);
        this.methods_count = classReader.readShort();
        this.methods = classReader.readMethods(this.methods_count, this);
        this.attributes_count = classReader.readShort();
        this.setAttributes(Attribute_infoParse.parse(attributes_count, classReader, this));
        return this;
    }

    public String getMagicInfo() {
        return "0x" + Integer.toHexString(magic);
    }

    public String getThis_className() {
        return ((CONSTANT_Class_info) constant_pool[this_class]).getClassName();
    }

    public String getSuper_className() {
        return  ((CONSTANT_Class_info) constant_pool[super_class]).getClassName();
    }

    public String[] getInterfaceNames() {
        String[] interfaceNames = new String[interfaces_count];
        for (int i = 0; i < interfaceNames.length; i++) {
            interfaceNames[i] = ((CONSTANT_Class_info)constant_pool[interfaces[i]]).getClassName();
        }
        return interfaceNames;
    }

}
